﻿using System;
using System.Threading.Tasks;
using FreshMeat.Threading;

namespace FreshMeat.Storage
{
   /// <summary>
   /// A context through which operations are performed against a store.
   /// Operations made through a context are isolated from operations made through other contexts.
   /// Contexts should be used and disposed as quickly as possible.
   /// </summary>
   public abstract class StoreContext
   {
      readonly ILock resourceLock;
      bool locked;

      /// <summary>
      /// Creates an instance.
      /// </summary>
      /// <param name="resourceLock">Prevent multiple contexts from simultaneously accessing the store.</param>
      protected StoreContext(ILock resourceLock)
      {
         this.resourceLock = resourceLock;
      }

      /// <summary>
      /// Obtains the lock on a just-in-time basis.
      /// Every operation acting on the store must call this first.
      /// </summary>
      protected void Lock()
      {
         if (!locked)
         {
            resourceLock.Wait();
            locked = true;
         }
      }

      /// <summary>
      /// Obtains the lock on a just-in-time basis.
      /// Every operation acting on the store must call this first.
      /// </summary>
      protected async Task LockAsync()
      {
         if (!locked)
         {
            await resourceLock.WaitAsync();
            locked = true;
         }
      }

      /// <summary>
      /// Releases the lock if necessary.
      /// </summary>
      public void Dispose()
      {
         if (locked)
            resourceLock.Done();
      }
   }
}